import { NextApiRequest } from "next";

interface IpInfo {
    ip: string;
    isPrivate: boolean;
    isIPv6: boolean;
    isLocalhost: boolean;
}

class IpUtils {
    // IPv4 私有地址范围
    private static readonly PRIVATE_IPV4_RANGES = [
        { start: '10.0.0.0', end: '10.255.255.255' },      // A类私有地址
        { start: '172.16.0.0', end: '172.31.255.255' },    // B类私有地址
        { start: '192.168.0.0', end: '192.168.255.255' },  // C类私有地址
    ];

    // IPv6 私有地址前缀
    private static readonly PRIVATE_IPV6_PREFIXES = [
        'fc00::',      // 唯一本地地址 (ULA)
        'fd00::',      // 唯一本地地址 (ULA)
        'fe80::',      // 链路本地地址
        '::1',         // IPv6 本地回环
    ];

    // IPv4 本地回环地址
    private static readonly LOCALHOST_IPV4 = '127.0.0.1';

    /**
     * 获取客户端IP地址
     * @param req NextApiRequest对象
     * @returns IP地址字符串
     */
    static getIp(req: NextApiRequest): string {
        const ipInfo = this.getIpInfo(req);
        return ipInfo.ip;
    }

    /**
     * 获取详细的IP信息
     * @param req NextApiRequest对象
     * @returns IpInfo对象
     */
    static getIpInfo(req: NextApiRequest): IpInfo {
        // 优先使用 Vercel 提供的 x-real-ip
        const xRealIP = req.headers['x-real-ip'] as string;
        
        // 其次使用 x-forwarded-for（可能包含多个 IP，取第一个）
        const xForwardedFor = req.headers['x-forwarded-for'] as string;
        
        // 优先级：x-real-ip > x-forwarded-for > socket > connection
        let ip = xRealIP || (xForwardedFor ? xForwardedFor.split(',')[0].trim() : '');
        
        // 如果前面都没获取到，使用备用方式
        if (!ip) {
            const connectionRemoteAddress = req.socket?.remoteAddress;
            const socketRemoteAddress = req.connection?.remoteAddress;
            ip = connectionRemoteAddress || socketRemoteAddress || this.LOCALHOST_IPV4;
        }

        // 清理IP地址（移除端口号等）
        ip = this.cleanIp(ip);

        return {
            ip,
            isPrivate: this.isPrivateIp(ip),
            isIPv6: this.isIPv6(ip),
            isLocalhost: this.isLocalhost(ip)
        };
    }

    /**
     * 清理IP地址，移除端口号等额外信息
     * @param ip 原始IP地址
     * @returns 清理后的IP地址
     */
    private static cleanIp(ip: string): string {
        if (!ip) return this.LOCALHOST_IPV4;
        if (ip.includes('::ffff:')) {
            ip = ip.substring(ip.indexOf('::ffff:') + 7);
        }        
        // 移除IPv6的端口号 (格式: [::1]:8080)
        if (ip.includes('[') && ip.includes(']')) {
            ip = ip.substring(ip.indexOf('[') + 1, ip.indexOf(']'));
        }
        // 移除IPv4的端口号 (格式: 192.168.1.1:8080)
        else if (ip.includes(':')) {
            ip = ip.split(':')[0];
        }

        return ip;
    }

    /**
     * 判断是否为IPv6地址
     * @param ip IP地址
     * @returns 是否为IPv6
     */
    static isIPv6(ip: string): boolean {
        if (!ip) return false;
        
        // IPv6地址包含冒号，且不是IPv4的端口号格式
        if (ip.includes(':')) {
            // 检查是否为IPv4地址加端口号
            const parts = ip.split(':');
            if (parts.length === 2 && this.isIPv4(parts[0])) {
                return false;
            }
            return true;
        }
        
        return false;
    }

    /**
     * 判断是否为IPv4地址
     * @param ip IP地址
     * @returns 是否为IPv4
     */
    static isIPv4(ip: string): boolean {
        if (!ip) return false;
        
        // IPv4正则表达式
        const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
        return ipv4Regex.test(ip);
    }

    /**
     * 判断是否为私有IP地址
     * @param ip IP地址
     * @returns 是否为私有IP
     */
    static isPrivateIp(ip: string): boolean {
        if (!ip) return false;

        if (this.isIPv6(ip)) {
            return this.isPrivateIPv6(ip);
        } else {
            return this.isPrivateIPv4(ip);
        }
    }

    /**
     * 判断是否为IPv4私有地址
     * @param ip IPv4地址
     * @returns 是否为私有IPv4
     */
    private static isPrivateIPv4(ip: string): boolean {
        if (!this.isIPv4(ip)) return false;

        // 检查是否为本地回环地址
        if (ip === this.LOCALHOST_IPV4) return true;

        // 检查私有地址范围
        const ipNum = this.ipToNumber(ip);
        return this.PRIVATE_IPV4_RANGES.some(range => {
            const startNum = this.ipToNumber(range.start);
            const endNum = this.ipToNumber(range.end);
            return ipNum >= startNum && ipNum <= endNum;
        });
    }

    /**
     * 判断是否为IPv6私有地址
     * @param ip IPv6地址
     * @returns 是否为私有IPv6
     */
    private static isPrivateIPv6(ip: string): boolean {
        if (!this.isIPv6(ip)) return false;

        // 检查私有地址前缀
        return this.PRIVATE_IPV6_PREFIXES.some(prefix => {
            return ip.toLowerCase().startsWith(prefix.toLowerCase());
        });
    }

    /**
     * 判断是否为本地回环地址
     * @param ip IP地址
     * @returns 是否为本地回环
     */
    static isLocalhost(ip: string): boolean {
        if (!ip) return false;
        
        return ip === this.LOCALHOST_IPV4 || ip === '::1' || ip === 'localhost';
    }

    /**
     * 将IPv4地址转换为数字
     * @param ip IPv4地址
     * @returns 数字表示
     */
    private static ipToNumber(ip: string): number {
        const parts = ip.split('.');
        return (parseInt(parts[0]) << 24) + 
               (parseInt(parts[1]) << 16) + 
               (parseInt(parts[2]) << 8) + 
               parseInt(parts[3]);
    }

    /**
     * 获取IP地址类型描述
     * @param ip IP地址
     * @returns 类型描述
     */
    static getIpType(ip: string): string {
        if (!ip) return '未知';
        
        if (this.isLocalhost(ip)) return '本地回环';
        if (this.isPrivateIp(ip)) return this.isIPv6(ip) ? '私有IPv6' : '私有IPv4';
        return this.isIPv6(ip) ? '公网IPv6' : '公网IPv4';
    }

    /**
     * 验证IP地址格式
     * @param ip IP地址
     * @returns 是否有效
     */
    static isValidIp(ip: string): boolean {
        if (!ip) return false;
        
        return this.isIPv4(ip) || this.isIPv6(ip);
    }

    /**
     * 获取IP地址的详细信息（用于调试）
     * @param req NextApiRequest对象
     * @returns 详细信息对象
     */
    static getDetailedInfo(req: NextApiRequest): any {
        const ipInfo = this.getIpInfo(req);
        
        return {
            ...ipInfo,
            type: this.getIpType(ipInfo.ip),
            headers: {
                'x-real-ip': req.headers['x-real-ip'],
                'x-forwarded-for': req.headers['x-forwarded-for'],
                'x-forwarded-proto': req.headers['x-forwarded-proto'],
                'x-forwarded-host': req.headers['x-forwarded-host'],
            },
            socket: {
                remoteAddress: req.socket?.remoteAddress,
                remotePort: req.socket?.remotePort,
            },
            connection: {
                remoteAddress: req.connection?.remoteAddress,
                remotePort: req.connection?.remotePort,
            }
        };
    }
}

export default IpUtils; 